
package com.mephi.controller.finder;


import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.mephi.exception.IllegalGameStateException;
import com.mephi.gui.Field;
import com.mephi.gui.GUI;
import com.mephi.gui.Piece;
import com.mephi.interfaces.Chessboard;
import com.mephi.interfaces.Game;
import com.mephi.interfaces.PieceMoveFinder;
import com.mephi.model.Move;
import com.mephi.model.PieceMovement;
import com.mephi.util.AuxClass;
import com.mephi.util.CastlingSort;
import com.mephi.util.Constants;
import com.mephi.util.PieceColor;
import com.mephi.util.PieceSort;


/**
 * A default implementation. Creates long algebraic notation.
 * 
 * @author mephisto
 * 2011-06-23
 */
public class PieceMoveFinderImpl implements PieceMoveFinder
{
	/**
	 * 
	 * @param gameModel the model of the game to set
	 * @param chessboard the reference to chessboard to set
	 */
	public PieceMoveFinderImpl(Game<Move> gameModel, Chessboard chessboard)
	{
		setGameModel(gameModel);
		setChessboard(chessboard);
	}
	
	/**
	 * 
	 * @return the gameModel
	 */
	public Game<Move> getGameModel()
	{
		return gameModel;
	}

	/**
	 * 
	 * @param gameModel to the gameModel to set
	 * @throws IllegalArgumentException if gameModel is null
	 */
	public void setGameModel(Game<Move> gameModel)
	{
		AuxClass.checkArgument(gameModel, new IllegalArgumentException("gameModel is null!"));
		this.gameModel = gameModel;
	}

	/**
	 * 
	 * @return the chessboard
	 */
	public Chessboard getChessboard()
	{
		return chessboard;
	}

	/**
	 * 
	 * @param chessboard to the chessboard to set
	 * @throws IllegalArgument Exception if chessboard is null 
	 * @throws map which describes all fields doesn't have exactly
	 * 		   64 keys used for chess notation
	 */
	public void setChessboard(Chessboard chessboard)
	{
		AuxClass.checkArgument(chessboard, new IllegalArgumentException("chessboard is null!"));
		Map<String, Field> chessFieldMap = chessboard.getChessFieldsMap();
		if (chessFieldMap.size() != 64)
			new IllegalGameStateException("Chessboard has field " + chessFieldMap.size() + " fields. It should have 64!");
		for(int i=0, size = cols.length; i<size; i++)
			for(int j=0; j<size; j++)
			{
				StringBuilder strField = new StringBuilder(cols[i]).append(j);
				Field field = chessFieldMap.get(strField);
				if (field == null)
					new IllegalGameStateException("Chessboard has field " + strField + "which is null!");
				strField.delete(0, strField.length());
			}
		this.chessboard = chessboard;
	}
	
	/**
	 * Returns PieceMovement in the long notation of chess move. It converts
	 * short notation to long.
	 * 
	 * @param moveNumber the number of move to set
	 * @param pieceColor the PieceColor to set
	 * @return the long notation of chess move
	 * 
	 * @throws IllegalGameStateException if game is illegal state
	 * (calculating long algebraic move is not possible)
	 */
	@Override
	public PieceMovement find(int moveNumber, PieceColor pieceColor) 
			throws IllegalGameStateException
	{		
		StringBuilder strMove = null;
		if (pieceColor.equals(PieceColor.WHITE))
			strMove = new StringBuilder(gameModel.get(moveNumber-1).getWhiteMove());
		else
			strMove = new StringBuilder(gameModel.get(moveNumber-1).getBlackMove());
		
		//replaces an occurence of ':' with '-'
		int colonInd = strMove.indexOf(Constants.COLON_STRING);
		if (colonInd > 0)
			strMove.replace(colonInd, colonInd, Constants.PAUSE_STRING);
		
		//checks if it is long algebraic notation
		if (strMove.toString().indexOf(Constants.PAUSE_STRING) > 0 || 
				strMove.toString().indexOf(Constants.X_LETTER) > 0 || 
				strMove.toString().equals(Constants.SHORT_CASTLING) ||
				strMove.toString().equals(Constants.LONG_CASTLING))
			return new PieceMovement(moveNumber, strMove.toString(), pieceColor);
	
		PieceMovement pM = null;
		if (strMove.indexOf(Constants.R_CAPITAL_LETTER) > 0)
			pM = findRook(moveNumber, strMove, pieceColor);
		else if (strMove.indexOf(Constants.N_CAPITAL_LETTER) > 0)
			pM = findKnight(moveNumber, strMove, pieceColor);
		else if (strMove.indexOf(Constants.B_CAPITAL_LETTER) > 0)
			pM = findBishop(moveNumber, strMove, pieceColor);
		else if (strMove.indexOf(Constants.Q_CAPITAL_LETTER) > 0)
			pM = findQueen(moveNumber, strMove, pieceColor);
		else if (strMove.indexOf(Constants.K_CAPITAL_LETTER) > 0)
			pM = findKing(moveNumber, strMove, pieceColor);
		else
			pM = findPawn(moveNumber, strMove, pieceColor);
		
		return pM;
	}
	
	private PieceMovement findPawn(int moveNumber, StringBuilder strMove, PieceColor pieceColor) 
			throws IllegalGameStateException
	{
		int row = -1;
		List<String> possibleFields = new ArrayList<String>(4);
		//zrobic sprawdzenie czy strMove zaczyna sie z malej litery za pomoca regexpa
		//operation on moves which are describe like this 'c5, b7' 
		if (strMove.length() == 2)
		{
			row = Integer.parseInt(strMove.substring(1));
			if (row < 2 || row > 8)
				throw new IllegalGameStateException(strMove + "-impossible move!");
			if (row == 3 || row > 4)
				possibleFields.add(new StringBuilder(strMove.charAt(0)).append(row-1).toString());
			if (row == 4)
				possibleFields.add(new StringBuilder(strMove.charAt(0)).append(row-2).toString());
			int colNum = getNumberFromCol(strMove.substring(0, 1));
			
			if (colNum > 1 || colNum < 8)
			{
				possibleFields.add(new StringBuilder(cols[colNum-1]).append(row-1).toString());
				possibleFields.add(new StringBuilder(cols[colNum+1]).append(row-1).toString());
			} 
			else if (colNum == 1)
				possibleFields.add(new StringBuilder(cols[colNum+1]).append(row-1).toString());
			else if (colNum == 8)
				possibleFields.add(new StringBuilder(cols[colNum-1]).append(row-1).toString());
			else
				throw new IllegalGameStateException("No column is possible-illegal move: " + strMove);
			
			Map<String, Field> chessFieldsMap = chessboard.getChessFieldsMap();
			for(String it : possibleFields)
			{
				Piece p = chessFieldsMap.get(it).getPiece();
				if (p != null)
					if (p.getPieceColor().equals(pieceColor) && p.getPieceSort().equals(PieceSort.PAWN))
					{
						StringBuilder newMove = new StringBuilder(it).append(Constants.PAUSE_STRING).append(strMove);
						return new PieceMovement(moveNumber, newMove.toString(), pieceColor);
					}
	
			}	
				
			
		}
		return null;
	}
	
	private PieceMovement findRook(int moveNumber, StringBuilder strMove, PieceColor pieceColor) 
			throws IllegalGameStateException
	{
		return null;
	}
	
	private PieceMovement findKnight(int moveNumber, StringBuilder strMove, PieceColor pieceColor) 
			throws IllegalGameStateException
	{
		return null;
	}
	
	private PieceMovement findBishop(int moveNumber, StringBuilder strMove, PieceColor pieceColor) 
			throws IllegalGameStateException
	{
		return null;
	}
	
	private PieceMovement findQueen(int moveNumber, StringBuilder strMove, PieceColor pieceColor) 
			throws IllegalGameStateException
	{
		return null;
	}
	
	private PieceMovement findKing(int moveNumber, StringBuilder strMove, PieceColor pieceColor) 
			throws IllegalGameStateException
	{
		return null;
	}
	
	
	//return the number which indicates column or -1 if nothing was found
	private int getNumberFromCol(String col)
	{
		for(int i=0, size = cols.length; i<size; i++)
			if (col.equals(cols[i]))
				return i+1;
		return -1;
	}

	
	private static final String[] cols = {"a", "b", "c", "d", "e", "f", "g", "h"};
	private Game<Move> gameModel;
	private Chessboard chessboard;
}
